package com.pangu.task;

import com.pangu.RunAsyncTask;
import com.pangu.service.ActionException;
import com.pangu.task.mark.ATaskMark;
import com.pangu.tracker.AInvokeTracker;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Hashtable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 一个异步的操作，可以调用asyncTask的get方法外部自己决定同步的操作。
 * <p/>
 * Created by cxlin
 */
public final class AsyncOperation {

    public static final String TAG = AsyncOperation.class.getSimpleName();

    // 记录当前的任务列表，以便统一处理
    // 当执行注销的时候有必要停止和取消之当前提交的任务。
    private static Hashtable<ATaskMark, AsyncOperation> taskRecordMap = new Hashtable<ATaskMark, AsyncOperation>();

    // 具体任务执行方法
    // 安全考虑：弱应用
    private Method method;
    // 调用跟踪，用于处理成功或失败的结果。
    private AInvokeTracker invokeTracker;
    // 是否已经发生错误了
    private boolean isError;
    // 异步任务
    private RunAsyncTask asyncTask;
    // 当前任务的标示
    private ATaskMark taskMark;
    // 可能服务异常
    private ActionException actionException;
    // 附件,用于辅助数据处理
    private Object attach;

    public AsyncOperation(ATaskMark taskMark, Method method) {
        this.method = method;
        this.taskMark = taskMark;
        // 以流程开始立即标记为开始加载。
        taskMark.setTaskStatus(ATaskMark.HANDLE_DOING);
    }

    public AInvokeTracker getInvokeTracker() {
        return invokeTracker;
    }

    void setInvokeTracker(AInvokeTracker invokeTracker) {
        this.invokeTracker = invokeTracker;
    }

    public Object getAttach() {
        return attach;
    }

    public void setAttach(Object attach) {
        this.attach = attach;
    }

    /**
     * 执行一个异步任务
     *
     * @param service 方法所在对象
     * @param args    方法参数
     */
    public void excuteOperate(final Object service, final Object... args) {
        asyncTask = new RunAsyncTask() {

            @Override
            protected Object doInBackground(Object... params) {
                Object result = null;
                try {
                    if (method != null) {
                        result = method.invoke(service, args);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    // 标记错误
                    isError = true;
                    // 返回服务异常，以便tracker对异常类型进行特定处理。
                    if (e.getCause() instanceof ActionException) {
                        actionException = (ActionException) e.getCause();

                    } else if (e instanceof ActionException) {
                        actionException = (ActionException) e;
                    }

                    // 记录失败的方法
                    if (method != null) {
                    }
                }

                // 退出前先调用预处理
                if (invokeTracker != null && !isCancelled()) {
                    try {
                        invokeTracker.handleInvoikePrepare(taskMark);

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                return result;
            }

            @Override
            protected void onPostExecute(Object result) {
                // 取消的任务或者invokeTracker==null不需要在处理
                OperateResult operateResult = null;
                if (invokeTracker != null && !isCancelled()) {
                    // 以流程结束
                    if (isError) {
                        taskMark.setTaskStatus(ATaskMark.HANDLE_ERROR);
                    } else {
                        taskMark.setTaskStatus(ATaskMark.HANDLE_OVER);
                    }
                    operateResult = new OperateResult(taskMark);
                    operateResult.setResultData(result);
                    operateResult.setActionException(actionException);
                    operateResult.setAttach(attach);
                    try {
                        invokeTracker.handleInvokeOver(operateResult);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                    // 对应已经没有人认领的任务将直接终止
                } else {
                    if (taskMark != null) {
                        taskMark.setTaskStatus(ATaskMark.HANDLE_OVER);
                    }
                }

                // 移除任务
                if (taskMark != null) {
                    taskRecordMap.remove(taskMark);
                }

                // 这里在返回实际退出时进行通知
                if (invokeTracker != null) {
                    try {
                        invokeTracker.handleInvokeFinalize(operateResult, taskMark);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                // 清除引用
                taskMark = null;
                invokeTracker = null;
                actionException = null;
                method = null;
            }
        };
        asyncTask.execute();
        // 记录任务
        taskRecordMap.put(taskMark, this);

    }

    public final boolean clearAsysnTask(boolean mayInterruptIfRunning) {
        // 先移除任务
        taskRecordMap.remove(taskMark);
        // 取消任务
        boolean ok = doCancle(mayInterruptIfRunning);
        return ok;
    }

    private final boolean doCancle(boolean mayInterruptIfRunning) {
        // 取消任务
        boolean ok = asyncTask.cancel(mayInterruptIfRunning);

        // 具体任务执行方法
        method = null;
        // 调用跟踪，用于解释成功或失败的结果。
        invokeTracker = null;
        // 额外数
        taskMark.setTaskStatus(ATaskMark.HANDLE_OVER);
        taskMark = null;
        // 异常
        actionException = null;
        // 附件
        attach = null;

        return ok;
    }

    /**
     * 代理方法的调用必须咋执行execute之后
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     * @see RunAsyncTask#get()
     */
    public final Object get() throws InterruptedException, ExecutionException {
        return asyncTask.get();
    }

    public final Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
            TimeoutException {
        return asyncTask.get(timeout, unit);
    }

    public final RunAsyncTask.Status getStatus() {
        return asyncTask.getStatus();
    }

    public final boolean isCancelled() {
        return asyncTask.isCancelled();
    }

    /**
     * 是否已经存在同类的任务了
     *
     * @param taskMark
     * @return
     */
    public static boolean isTaskExist(ATaskMark taskMark) {
        AsyncOperation asyncOperation = taskRecordMap.get(taskMark);
        if (asyncOperation != null) {
            return true;

        } else {
            return false;
        }
    }

    /**
     * 获得指定任务
     *
     * @param taskMark 任务标记
     */
    static AsyncOperation getTaskByMark(ATaskMark taskMark) {
        return taskRecordMap.get(taskMark);
    }

    /**
     * 异步的任务
     *
     * @return
     */
    static Collection<AsyncOperation> asyncOperations() {
        return taskRecordMap.values();
    }

}
